﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ServiceModel;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Ninject;
using System.Net.Http;
using System.Net;
using Timetable.Utils.Exceptions;
using System.Configuration;

using Timetable.Site.Host.Course;
using Timetable.Site.Host.Faculty;
using Timetable.Site.Host.Group;
using Timetable.Site.Host.Lecturer;
using Timetable.Site.Host.Speciality;
using Timetable.Site.Host.Time;
using Timetable.Site.Host.Tutorial;
using Timetable.Site.Host.TutorialType;
using Timetable.Site.Host.Building;
using Timetable.Site.Host.Department;
using Timetable.Site.Host.Schedule;
using Timetable.Site.Host.ScheduleInfo;
//using Timetable.Site.Host.Auditorium;


namespace Timetable.Site.Controllers.Api
{
    public abstract class BaseApiController<T> : System.Web.Http.ApiController, INotifyPropertyChanged, IBaseController
    {

        #region Services
        protected readonly IFacultyService FacultyService;
        protected readonly ICourseService CourseService;
        protected readonly IGroupService GroupService;
        protected readonly ITutorialService TutorialService;
        protected readonly ITutorialTypeService TutorialTypeService;
        protected readonly ISpecialityService SpecialityService;
        protected readonly ITimeService TimeService;
        protected readonly ILecturerService LecturerService;
        protected readonly IBuildingService BuildingService;
        protected readonly IDepartmentService DepartmentService;
        protected readonly IScheduleService ScheduleService;
        protected readonly IScheduleInfoService ScheduleInfoService;
        //protected readonly IAuditoriumService AuditoriumService;
 
 
        #endregion

        public BaseApiController()
        {
            FacultyService = GetService<IFacultyService>("FacultyServiceAddress");
            CourseService = GetService<ICourseService>("CourseServiceAddress");
            GroupService = GetService<IGroupService>("GroupServiceAddress");
            TutorialService = GetService<ITutorialService>("TutorialServiceAddress");
            TutorialTypeService = GetService<ITutorialTypeService>("TutorialTypeServiceAddress");
            SpecialityService = GetService<ISpecialityService>("SpecialityServiceAddress");
            TimeService = GetService<ITimeService>("TimeServiceAddress");
            LecturerService = GetService<ILecturerService>("LecturerServiceAddress");
            BuildingService = GetService<IBuildingService>("BuildingServiceAddress");
            DepartmentService = GetService<IDepartmentService>("DepartmentServiceAddress");
            ScheduleService = GetService<IScheduleService>("ScheduleServiceAddress");
            ScheduleInfoService = GetService<IScheduleInfoService>("ScheduleInfoServiceAddress");
            //ScheduleInfoService = GetService<IAuditoriumService>("AuditoriumServiceAddress");
        }

        protected T GetService<T>(string serviceName)
        {
            var url = ConfigurationManager.AppSettings[serviceName];

            if (String.IsNullOrEmpty(url))
                throw new ArgumentNullException("url");

            var myBinding = new BasicHttpBinding();
            var myEndpoint = new EndpointAddress(url);
            var myChannelFactory = new ChannelFactory<T>(myBinding, myEndpoint);
            var host = myChannelFactory.CreateChannel();

            return host;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
        
        protected HttpResponseMessage Response;

        protected HttpResponseMessage CreateResponse<T>(Func<T> func)
        {
            try
            {
                var result = func();

                Response = Request.CreateResponse<T>(HttpStatusCode.OK, result);
            }
            catch (EntityNotFoundException ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.NotFound, ex);
            }
            catch (Exception ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
            }

            return Response;
        }

        protected HttpResponseMessage CreateResponse<T1, T2>(Func<T1, T2> func, T1 arg)
        {
            try
            {
                var result = func(arg);

                Response = Request.CreateResponse<T2>(HttpStatusCode.OK, result);
            }
            catch (EntityNotFoundException ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.NotFound, ex);
            }
            catch (Exception ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
            }

            return Response;
        }

        protected HttpResponseMessage CreateResponse<T1, T2, T3>(Func<T1, T2, T3> func, T1 arg1, T2 arg2)
        {
            try
            {
                var result = func(arg1, arg2);

                Response = Request.CreateResponse(HttpStatusCode.OK, result);
            }
            catch (EntityNotFoundException ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.NotFound, ex.ToString());
            }
            catch (Exception ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
            }

            return Response;
        }

        protected HttpResponseMessage CreateResponse<T1, T2, T3, T4>(Func<T1, T2, T3, T4> func, T1 arg1, T2 arg2, T3 arg3)
        {
            try
            {
                var result = func(arg1, arg2, arg3);

                Response = Request.CreateResponse(HttpStatusCode.OK, result);
            }
            catch (EntityNotFoundException ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.NotFound, ex.ToString());
            }
            catch (Exception ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
            }

            return Response;
        }



        protected HttpResponseMessage CreateResponse<T1, T2, T3, T4, T5>(Func<T1, T2, T3, T4, T5> func, T1 arg1, T2 arg2, T3 arg3, T4 arg4)
        {
            try
            {
                var result = func(arg1, arg2, arg3, arg4);

                Response = Request.CreateResponse(HttpStatusCode.OK, result);
            }
            catch (EntityNotFoundException ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.NotFound, ex.ToString());
            }
            catch (Exception ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
            }

            return Response;
        }

        protected HttpResponseMessage CreateResponse(Action action)
        {
            try
            {
                action();

                Response = Request.CreateResponse(HttpStatusCode.OK);
            }
            catch (EntityNotFoundException ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.NotFound, ex);
            }
            catch (Exception ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
            }

            return Response;
        }

        protected HttpResponseMessage CreateResponse<T>(Action<T> action, T arg)
        {
            try
            {
                action(arg);

                Response = Request.CreateResponse(HttpStatusCode.OK);
            }
            catch (EntityNotFoundException ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.NotFound, ex);
            }
            catch (Exception ex)
            {
                Response = Request.CreateResponse(HttpStatusCode.InternalServerError, ex);
            }

            return Response;
        }
    }
}
